package com.qcby.llmtchstd.service.Impl;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.qcby.llmtchstd.dao.ExamPaperDao;
import com.qcby.llmtchstd.dto.ExamPaperDto;
import com.qcby.llmtchstd.entity.Exam;
import com.qcby.llmtchstd.service.OfficeService;
import com.qcby.llmtchstd.utils.BrowserUtils;
import com.qcby.llmtchstd.utils.OfficeUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class OfficeServiceImpl implements OfficeService {

    public static final String EXAM_PAPER_TEMPLATE = "classpath:templates/exam.docx";

    @Resource
    private ExamPaperDao examPaperDao;
    @Resource
    private ResourceLoader resourceLoader;

    @Override
    public ExamPaperDto getExamPaperById(Long paperId) {
        Exam exam = examPaperDao.selectById(paperId);
        return exam != null ? convertExamToDto(exam) : null;
    }

    @Override
    public XWPFDocument generateExamPaper(ExamPaperDto paperDto) {
        try {
            InputStream templateStream = resourceLoader.getResource(EXAM_PAPER_TEMPLATE).getInputStream();
            XWPFDocument document = new XWPFDocument(templateStream);

            Map<String, Object> dataMap = OfficeUtils.objectToMap(paperDto);

            // 格式化所有题型（保留数据库原有换行符，同时补充必要换行）
            dataMap.put("{{choice_questions}}", formatChoiceQuestions(paperDto.getChoiceQuestions()));
            dataMap.put("{{fill_questions}}", formatFillQuestions(paperDto.getFillQuestions()));
            dataMap.put("{{judge_questions}}", formatJudgeQuestions(paperDto.getJudgeQuestions()));
            dataMap.put("{{essay_questions}}", formatEssayQuestions(paperDto.getEssayQuestions()));
            dataMap.put("{{calculate_questions}}", formatCalculateQuestions(paperDto.getCalculateQuestions()));

            OfficeUtils.paragraphTextFilling(document, dataMap);
            return document;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void downloadExamPaper(XWPFDocument document, ExamPaperDto paperDto,
                                  HttpServletResponse response, HttpServletRequest request) {  // 新增request参数
        try {
            String fileName = paperDto.getPaperName() + ".docx";
            // 编码后的文件名
            String encodedFileName = BrowserUtils.encodeFileName(request, fileName);
// 强制设置响应头（避免被其他拦截器修改）
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
// 补充 MIME 类型和编码
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setCharacterEncoding("UTF-8");

            // 3. 输出文件流
            document.write(response.getOutputStream());
            document.close();  // 直接写入响应流，减少中间字节数组操作
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件下载失败：" + e.getMessage());
        }
    }

    private ExamPaperDto convertExamToDto(Exam exam) {
        ExamPaperDto dto = new ExamPaperDto();
        dto.setPaperName(exam.getExamName());
        dto.setExamId(exam.getId().intValue());

        // 直接保留数据库中的JSON字符串（含原有\r\n换行符）
        dto.setChoiceQuestions(exam.getChoiceQuestions());
        dto.setFillQuestions(exam.getFillQuestions());
        dto.setJudgeQuestions(exam.getJudgeQuestions());
        dto.setEssayQuestions(exam.getEssayQuestions());
        dto.setCalculateQuestions(exam.getCalculateQuestions());

        // 计算题目数量和总分
        List<Question> choiceList = parseJsonToQuestions(exam.getChoiceQuestions());
        dto.setChoiceCount(choiceList.size());
        dto.setChoiceTotalScore(calculateTotalScore(choiceList));

        List<Question> fillList = parseJsonToQuestions(exam.getFillQuestions());
        dto.setFillCount(fillList.size());
        dto.setFillTotalScore(calculateTotalScore(fillList));

        List<Question> judgeList = parseJsonToQuestions(exam.getJudgeQuestions());
        dto.setJudgeCount(judgeList.size());
        dto.setJudgeTotalScore(calculateTotalScore(judgeList));

        List<Question> essayList = parseJsonToQuestions(exam.getEssayQuestions());
        dto.setEssayCount(essayList.size());
        dto.setEssayTotalScore(calculateTotalScore(essayList));

        List<Question> calculateList = parseJsonToQuestions(exam.getCalculateQuestions());
        dto.setCalculateCount(calculateList.size());
        dto.setCalculateTotalScore(calculateTotalScore(calculateList));

        return dto;
    }

    // 解析JSON为Question列表（用于计算数量和分数）
    private List<Question> parseJsonToQuestions(String json) {
        List<Question> questions = new ArrayList<>();
        if (json == null || json.trim().isEmpty() || "[]".equals(json.trim())) {
            return questions;
        }

        try {
            JsonArray jsonArray = new Gson().fromJson(json, JsonArray.class);
            for (JsonElement element : jsonArray) {
                JsonObject obj = element.getAsJsonObject();
                Question q = new Question();
                q.setId(obj.get("id").getAsInt());
                q.setContent(obj.get("content").getAsString());
                q.setScore(obj.get("score").getAsInt());

                if (obj.has("options")) {
                    Type type = new TypeToken<List<String>>() {}.getType();
                    q.setOptions(new Gson().fromJson(obj.get("options"), type));
                }
                questions.add(q);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return questions;
    }

    private int calculateTotalScore(List<Question> questions) {
        return questions.stream().mapToInt(Question::getScore).sum();
    }

    // 格式化选择题（核心修复：保留数据库换行+去重选项）
    private String formatChoiceQuestions(String json) {
        List<Question> questions = parseJsonToQuestions(json);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < questions.size(); i++) {
            Question q = questions.get(i);
            // 题目内容（保留数据库原有换行，再补充一个换行）
            sb.append(i + 1).append("、").append(q.getContent())
                    .append("（").append(q.getScore()).append("分）")
                    .append("\r\n");  // 强制换行

            // 处理选项（移除重复的A.前缀，保留选项内容）
            List<String> options = q.getOptions();
            if (options != null) {
                for (String option : options) {
                    // 移除选项中已有的[A-Z].前缀（如"A.String"→"String"）
                    String cleanOption = option.replaceAll("^[A-Z]\\.", "");
                    // 重新添加正确的前缀（A.、B.）并换行
                    sb.append("   ").append((char) ('A' + options.indexOf(option))).append(".")
                            .append(cleanOption).append("\r\n");
                }
            }
            // 题目间空行（用两个换行实现）
            sb.append("\r\n");
        }
        return sb.toString();
    }

    // 格式化填空题（保留数据库换行，补充空行）
    private String formatFillQuestions(String json) {
        List<Question> questions = parseJsonToQuestions(json);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < questions.size(); i++) {
            Question q = questions.get(i);
            sb.append(i + 1).append("、").append(q.getContent())
                    .append("（").append(q.getScore()).append("分）")
                    .append("\r\n\r\n");  // 题目后空行
        }
        return sb.toString();
    }

    // 格式化判断题（同上）
    private String formatJudgeQuestions(String json) {
        List<Question> questions = parseJsonToQuestions(json);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < questions.size(); i++) {
            Question q = questions.get(i);
            sb.append(i + 1).append("、").append(q.getContent())
                    .append("（").append(q.getScore()).append("分）")
                    .append("\r\n\r\n");
        }
        return sb.toString();
    }

    // 格式化简答题
    private String formatEssayQuestions(String json) {
        List<Question> questions = parseJsonToQuestions(json);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < questions.size(); i++) {
            Question q = questions.get(i);
            sb.append(i + 1).append("、").append(q.getContent())
                    .append("（").append(q.getScore()).append("分）")
                    .append("\r\n\r\n");
        }
        return sb.toString();
    }

    // 格式化计算题
    private String formatCalculateQuestions(String json) {
        List<Question> questions = parseJsonToQuestions(json);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < questions.size(); i++) {
            Question q = questions.get(i);
            sb.append(i + 1).append("、").append(q.getContent())
                    .append("（").append(q.getScore()).append("分）")
                    .append("\r\n\r\n");
        }
        return sb.toString();
    }

    // 内部题目实体类
    private static class Question {
        private Integer id;
        private String content;
        private Integer score;
        private List<String> options;

        public Integer getId() { return id; }
        public void setId(Integer id) { this.id = id; }
        public String getContent() { return content; }
        public void setContent(String content) { this.content = content; }
        public Integer getScore() { return score; }
        public void setScore(Integer score) { this.score = score; }
        public List<String> getOptions() { return options; }
        public void setOptions(List<String> options) { this.options = options; }
    }
}